package com.jamie.jvm.volatile_;

import java.util.concurrent.TimeUnit;

/**
 * Volatile可见性验证
 * 1.1 假如 int number = 0; number变量之前根本没有加volatile关键字修饰
 * 1.2 添加了volatile可以解决了可见性问题。
 *
 * 2. 验证volatile不保证原子性
 * 2.1 原子性的指的是什么意思？- 不可分割，完整性，也即某个线程正在做某个业务时，中间不可以被加塞或者被分割，需要整体完整，要么同时成功，要不同时失败。
 * 2.2 volatile不保证原子性的案例演示
 * 2.3 为什么不保证？
 * 2.4 如果保证原子性
 * 2.4.1 加sync
 * 2.4.2 使用juc下的AtomicInteger
 * @author jamie
 */
public class VolatileDemo {

    public static void main(String[] args) {
        MyData myData = new MyData();
        for(int i = 0; i < 20; i++){
            new Thread(() -> {
                for(int i1 = 0; i1 < 1000; i1++){
                    myData.addPlusPlus();
                }
            }, String.valueOf(i)).start();
        }
        //  需要等待上面20个线程都全部完成后，再用main线程取得最终值，原子性合理的情况是20000
        while(Thread.activeCount() > 2){
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + " finally number value:" + myData.number);
    }

    /**
     * volatile 可以保证可加性，及时通知其他的线程，主物理内存的值已经被修改
     */
    private static void seeOKByVolatile() {
        MyData myData = new MyData();
        // 第一个线程
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t come in");
            //   暂停一下线程
            try{
                TimeUnit.SECONDS.sleep(3);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t updated number value:" + myData.number);
            myData.addTo60();
        }, "AAA").start();

        // 第2个线程就是我们的main线程
        while(myData.number == 0){
            // main线程就一直在这里等待，知道number不等于0
        }
        System.out.println(Thread.currentThread().getName() + "\t mussion is over");
    }

}

/**
 * volatile_.MyData.java ===> volatile_.MyData.class ===> JVM字节码
 */
class MyData {

    volatile int number = 0;

    public void addTo60() {
        this.number = 60;
    }

    // 请注意，此时number前面是加了volatile关键字修饰的，volatile不保证原子性
    public void addPlusPlus() {
        number++;
    }

}